/*
 * Creado por NIN
 * User: sebastian.lucas
 * Date: 14/05/2007
 * Time: 16:28
 */

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.CSharp;
using System.IO;
using System.CodeDom.Compiler;
using System.Reflection;


namespace CSE
{
	/// <summary>
	/// Description of Plugins.
	/// </summary>
	public class Plugins
	{
	    /*
	     * Constants
	     */
	    private static readonly string PLUGINS_DIR = "\\plugins\\";
	    private static readonly string []ASSEMBLYS = new string[] {"System.dll",
	                                                               "System.Xml.dll",
	                                                               "System.Data.dll",
	                                                               "System.Drawing.dll",
	                                                               "System.Windows.Forms.dll",
	                                                               "CSE.exe"};
	    private static readonly string ENTRY_POINT = "main";
	    
	    public static string Path = "";
	    
	    /*
	     * Variables
	     */
	    private static Dictionary<string, Assembly> Plugins_Dic = null;
	    
	    /*
	     * Init
	     */
	    public static void Init ()
	    {
	        if (Plugins_Dic == null)
	        {
	            Plugins_Dic = new Dictionary<string, Assembly>();
	        }
	        
	        FindAndInstall();
	    }
	    
	    /*
	     * FindAndInstall
	     */
	    public static void FindAndInstall ()
	    {
	        DirectoryInfo di = new DirectoryInfo(Directory.GetCurrentDirectory() + PLUGINS_DIR);
	    	FileInfo[] rgFiles = null;
	    	
	    	Path = Directory.GetCurrentDirectory() + PLUGINS_DIR;
	    	
	    	try
            {
		    	rgFiles = di.GetFiles("*.cs");
			}
	    	catch (Exception e)
            {
	    		Utils.Trace(">> Plugins::FindAndInstall() fail, check dirs!");
	    		Utils.Trace("Exception: " + e.Message);
	    		return;
	    	}
	    	
	    	foreach(FileInfo fi in rgFiles)
            {
				Compile(fi.FullName, fi.Name.Substring(0, fi.Name.IndexOf(".")));
                Run(fi.Name.Substring(0, fi.Name.IndexOf(".")));
			}
	    }
	    
	    /*
	     * Compile
	     */
	    private static bool Compile(string filename, string name)
        {
	        int i=0;
	        string messages = "";
	        CSharpCodeProvider _codeProv = new CSharpCodeProvider();
            CompilerParameters _params = new CompilerParameters();
            
            try
            {
                _params.GenerateExecutable = false;
                _params.GenerateInMemory = true;
                _params.CompilerOptions = "/optimize /unsafe";
                
                for (i=0; i<ASSEMBLYS.Length; i++)
                {
                    _params.ReferencedAssemblies.Add(ASSEMBLYS[i]);
                }
                
                CompilerResults result = _codeProv.CompileAssemblyFromFile(_params, filename);

                if (result.Errors.Count > 0)
                {
                    messages += "Error during '" + filename + "' compilation.\n";
                    for (i=0; i<result.Errors.Count; i++)
                    {
                        messages += "\t" + result.Errors[i].ErrorText + " (Line " + result.Errors[i].Line + ")\n";
                    }
                }
                else
                {
                    Utils.Trace("Loaded '" + filename + "'");

                    Assembly asmb = result.CompiledAssembly;
                    Plugins_Dic.Add(name, asmb);
                    
                    return true;
         
                }
            }
            catch (Exception e)
            {
                messages += "Error during '" + filename + "' compilation (" + e.Message + ")\n";
            }

            Utils.MsgBox(messages);
            return false;
        }
	    
	    /*
	     * Run
	     */
	    public static void Run(string name)
        {
            if (!Plugins_Dic.ContainsKey(name))
            {
                Utils.Trace("Script '" + name + "' not found.");
                return;
            }

            Assembly asmb = Plugins_Dic[name];
            System.Type scriptType = asmb.GetType(name, false, true);

            if (scriptType != null)
            {
                try
                {
                    System.Object obj = scriptType.InvokeMember(ENTRY_POINT, BindingFlags.InvokeMethod, null, null, null);
                }
                catch (Exception e)
                {
                    Utils.Trace("Error running '" + name + "'.");
                    Utils.Trace("\t" + e.Message + "\n");
                }
            }
            else
            {
                Utils.Trace("Class '" + name + "' not found.");
            }
        }
	}
}
